#include <iostream>

#include <boost/noncopyable.hpp>

#include <kuai/misc/typedef.hpp>
#include <kuai/misc/strtool.hpp>
#include <kuai/misc/funcman.hpp>


#ifndef _KUAIJOB_JOB_H_
#define _KUAIJOB_JOB_H_

namespace kuai {

	class BasicJob
		: public boost::noncopyable
	{
	public:
		virtual void parse(std::istream& input, std::ostream& output, std::ostream& error) = 0;

		class BasicJobCreator
		{ 
		public:
			virtual boost::shared_ptr<BasicJob> create() const = 0;
			virtual void help(std::ostream& output) const = 0;
		};

		static bool isEndJob(const String& line) {
			String ss = boost::algorithm::trim_copy(line);
			return boost::algorithm::iequals(ss, "endjob") || boost::algorithm::iequals(ss, "runjob");
		};

		static bool isAbort(const String& line) {
			String ss = boost::algorithm::trim_copy(line);
			return boost::algorithm::iequals(ss, "abort");
		};
		static bool isRemark(const String& line) {
			size_t i;
			for (i = 0; i < line.size(); ++i) {
				if (!isspace(line[i])) {
					break;
				}
			}
			return i == line.size() || line[i] == '#';
		};
		static bool isEmbed(const String& line) {
			String ss = boost::algorithm::trim_copy(line);
			return boost::algorithm::iequals(ss, "embed");
		};
		static bool isEnd(const String& line) {
			String ss = boost::algorithm::trim_copy(line);
			return boost::algorithm::iequals(ss, "end");
		};
	};

	class SequenceJob
		: public BasicJob
	{
	public:
		virtual void parse(std::istream& input, std::ostream& output, std::ostream& error);
		virtual void pushParameter(const String& key, const String& data, std::ostream& output, std::ostream& error) = 0;
		virtual void doJob(std::ostream& output, std::ostream& error) = 0;
	};

	class ParameterJob
		: public SequenceJob
	{
	public:
		virtual void pushParameter(const String& key, const String& data, std::ostream& output, std::ostream& error);
		virtual void doJob(std::ostream& output, std::ostream& error);
		virtual void doJob(std::ostream& osOutput, std::ostream& osError, StringMap& par) = 0;
	
		static RealNumber getParameter(StringMap& par, const String& key, RealNumber def);
		static String getParameter(StringMap& par, const String& key, String def);
		static String getParameter(StringMap& par, const String& key, const Char def[]);
		static size_t getParameter(StringMap& par, const String& key, size_t def);
		static String getParameter(StringMap& par, const String& key);
		static bool getParameter(StringMap& par, const String& key, bool def);

	protected:
		StringMap parameters;

	};


	class JobManager
		: public FunctionManager<String, BasicJob::BasicJobCreator>, boost::noncopyable
	{
	private:
		JobManager();

	public:
		void parse(std::istream& input = std::cin, std::ostream& output = std::cout, std::ostream& error = std::cerr) const;

	public:
		static JobManager& getInstance();
		static String uniformCommand(const String& command);
	};

}

#define DECLARE_JOB_CREATOR(jobname)										\
	public:																	\
		class Creator														\
			: public BasicJob::BasicJobCreator								\
		{																	\
		public:																\
			virtual boost::shared_ptr<BasicJob> create() const				\
			{																\
				return boost::shared_ptr<BasicJob>(new jobname);			\
			}																\
			virtual void help(std::ostream& output) const;					\
			static const char* TAG;											\
		};
		


#define REGISTER_JOB_CREATOR(jobname)										\
	kuai::JobManager::getInstance().insert(									\
	std::make_pair(kuai::JobManager::uniformCommand(jobname::Creator::TAG),	\
		kuai::JobManager::FunctionPointer(new jobname::Creator)));				

#define IMPLEMENT_JOB_CREATOR(jobname, tag)									\
	const char* jobname::Creator::TAG = #tag;

#define JOB_HELP_FUNCTION(jobname, output)									\
	void jobname::Creator::help(std::ostream& output) const						

#endif

